//
//  TNGuideView.swift
//  TNMeeting
//
//  Created by tenroadshow on 17.1.22.
//
import UIKit


public enum NNCommonGuideType: String {
    case detailPage = "kGuideKeyOfDetailPage"
    
}


struct NNGuideManager {
    
    // 判断是否展示
    static func checkDidShowed(type: NNCommonGuideType) -> Bool {
        if let _ = UserDefaults.standard.string(forKey: type.rawValue) {
            return true
        }else {
            return false
        }
    }
    
    // 展示后记录
    static func recordShowed(type: NNCommonGuideType) {
        UserDefaults.standard.setValue(type.rawValue, forKey: type.rawValue)
        UserDefaults.standard.synchronize()
    }
    
}

public struct NNGuideItem {
    
    var overlayRect: CGRect = .zero
    
    var message: String?
    
    
    var itemSpace: CGFloat = 10.0
    
    enum GuideImageDirection: Int {
        case top = 0
        case topRight
        case topLeft

        case bottom
        case bottomRight
        case bottomLeft
    }

    var direction: GuideImageDirection = .top
    

    fileprivate var innerImageSize = CGSize(width: 117, height: 117)
    fileprivate var lineImageCenter: CGPoint {
        switch direction {
        case .bottom:
            return CGPoint(x: overlayRect.midX,
                           y: overlayRect.minY - itemSpace - innerImageSize.height * 0.5)
        case .bottomLeft:
            return CGPoint(x: overlayRect.minX + innerImageSize.width * 0.5,
                           y: overlayRect.minY - itemSpace - innerImageSize.height * 0.5)
        case .bottomRight:
            return CGPoint(x: overlayRect.minX - innerImageSize.width * 0.5,
                           y: overlayRect.minY - itemSpace - innerImageSize.height * 0.5)
        case .top:
            return CGPoint(x: overlayRect.midX,
                           y: overlayRect.maxY + itemSpace + innerImageSize.height * 0.5)
        case .topLeft:
            return CGPoint(x: overlayRect.maxX + innerImageSize.width * 0.5,
                           y: overlayRect.maxY + itemSpace + innerImageSize.height * 0.5)
        case .topRight:
            return CGPoint(x: overlayRect.minX - innerImageSize.width * 0.5,
                           y: overlayRect.maxY + itemSpace + innerImageSize.height * 0.5)
        }
    }
}

open class NNGuideView: UIView {
    fileprivate lazy var tapGesture: UITapGestureRecognizer = {
        let tap = UITapGestureRecognizer(target: self, action: #selector(touchedAction(tap:)))
        return tap
    }()
    
    fileprivate lazy var rectLayer: CAShapeLayer = {
        let rectLayer = CAShapeLayer()
        rectLayer.frame = UIScreen.main.bounds
        rectLayer.fillColor = UIColor.red.cgColor
        rectLayer.strokeColor = UIColor.purple.cgColor
        self.layer.mask = rectLayer
        return rectLayer
    }()
    
    // 箭头
    fileprivate lazy var arrowContainer: NNArrowLineContainer = {
        let container = NNArrowLineContainer(frame: .zero)
        return container
    }()
    
    fileprivate lazy var introduceLabel: UILabel = {
        let label = UILabel()
        label.font = UIFont.boldSystemFont(ofSize: 20)
        label.textColor = UIColor.white
        label.textAlignment = .center
        label.numberOfLines = 0
        return label
    }()
    
    
    
    fileprivate var weakWindow: UIWindow?
    fileprivate var items: [NNGuideItem] = []
    fileprivate var currentIndex: Int = 0
    
    
    public var shouldOnlyWhereTouched: Bool = false
    
    
    
    override init(frame: CGRect) {
        super.init(frame: UIScreen.main.bounds)
        setupUI()
    }
    
    required public init?(coder: NSCoder) {
        super.init(coder: coder)
        setupUI()
    }
    
    private func setupUI() {
        translatesAutoresizingMaskIntoConstraints = false
        backgroundColor = UIColor(white: 0, alpha: 0.5)
        isUserInteractionEnabled = true
        addGestureRecognizer(self.tapGesture)
        addSubview(arrowContainer)
        addSubview(introduceLabel)
    }
    
    /// 获取临时window
    fileprivate func fetchWeakWindow() -> UIWindow {
        let targetWindow = UIWindow(frame: UIScreen.main.bounds)
        targetWindow.windowLevel = .statusBar
        targetWindow.makeKeyAndVisible()
        return targetWindow
    }
    
    
    fileprivate func showItem(index: Int = 0) {
        if index >= items.count { return }
        let item = items[index]
        let path = UIBezierPath(rect: UIScreen.main.bounds)
        path.append(UIBezierPath(roundedRect: item.overlayRect,
                                 byRoundingCorners: .allCorners,
                                 cornerRadii: CGSize(width: 5.0, height: 5.0)).reversing())
        if index == 0 {
            arrowContainer.center = item.lineImageCenter
            self.rectLayer.path = path.cgPath
            self.updateTransfrom(item: item)
        }else {
            UIView.animate(withDuration: 0.5) {
                self.arrowContainer.center = item.lineImageCenter
                self.updateTransfrom(item: item)
            }
            let animation = CABasicAnimation(keyPath: "path")
            animation.timingFunction = .init(name: .easeInEaseOut)
            animation.duration = 0.5
            animation.isRemovedOnCompletion = true
            animation.fillMode = .forwards
            
            if let path = rectLayer.path {
                animation.fromValue = path
            }else {
                animation.fromValue = path.cgPath
            }
            animation.toValue   = path.cgPath
            rectLayer.add(animation, forKey: "path")
            rectLayer.path = path.cgPath
        }
    }
    
    func updateTransfrom(item: NNGuideItem) {
        
        self.arrowContainer.direction = item.direction
        
        var msgSize: CGSize = .zero
        if let msg = item.message, !msg.isEmpty {
            msgSize = msg.boundingRect(with: CGSize(width: CommonConstant.screenW, height: CommonConstant.screenW),
                             options: [.usesFontLeading, .usesLineFragmentOrigin],
                                       attributes: [NSAttributedString.Key.font: introduceLabel.font!], context: nil).size
            msgSize = CGSize(width: msgSize.width + 10, height: msgSize.height + 10)
            
            introduceLabel.text = msg
        }else {
            introduceLabel.text = nil
        }
        
        
        
        switch item.direction {
        case .top:
            // 箭头垂直向上
            introduceLabel.frame  = CGRect(x: arrowContainer.frame.midX - msgSize.width * 0.5,
                                           y: arrowContainer.frame.maxY + item.itemSpace,
                                           width: msgSize.width, height: msgSize.height)

        case .topRight:
            // 箭头右上
            introduceLabel.frame  = CGRect(x: arrowContainer.frame.minX - msgSize.width * 0.5,
                                           y: arrowContainer.frame.maxY + item.itemSpace,
                                           width: msgSize.width, height: msgSize.height)

        case .topLeft:
            // 箭头左上
            introduceLabel.frame  = CGRect(x: arrowContainer.frame.maxX + msgSize.width * 0.5,
                                           y: arrowContainer.frame.maxY + item.itemSpace,
                                           width: msgSize.width, height: msgSize.height)

        case .bottom:
            // 箭头垂直向下
            introduceLabel.frame  = CGRect(x: arrowContainer.frame.minX,
                                           y: arrowContainer.frame.minY - item.itemSpace - msgSize.height,
                                           width: msgSize.width, height: msgSize.height)

        case .bottomRight:
            // 箭头右下
            introduceLabel.frame  = CGRect(x: arrowContainer.frame.minX - msgSize.width * 0.5,
                                           y: arrowContainer.frame.minY - item.itemSpace - msgSize.height,
                                           width: msgSize.width, height: msgSize.height)

        case .bottomLeft:
            // 箭头左下
            introduceLabel.frame  = CGRect(x: arrowContainer.frame.minX + msgSize.width * 0.5,
                                           y: arrowContainer.frame.minY - item.itemSpace - msgSize.height,
                                           width: msgSize.width, height: msgSize.height)
        }
    }
    
    
    fileprivate func deleteSelf() {
        weakWindow?.removeFromSuperview()
        weakWindow = nil
        removeFromSuperview()
    }
}

// public
extension NNGuideView {
    
    // 通过目标视图显示引导（默认选择图片显示的位置）
    func showGuide(by infos: [(UIView, NNGuideItem)]) {
        weakWindow = fetchWeakWindow()
        guard let targetWindow = weakWindow else { return deleteSelf() }
        currentIndex = 0
        targetWindow.addSubview(self)
        var tempItems: [NNGuideItem] = []
        infos.forEach { info in
            let rect = info.0.convert(info.0.bounds, to: targetWindow)
            
            let item = NNGuideItem(overlayRect: rect,
                                   message: info.1.message,
                                   direction: info.1.direction)
                tempItems.append(item)
        }
        self.items = tempItems
        showItem(index: currentIndex)
    }
}



// 事件
extension NNGuideView: UIGestureRecognizerDelegate {
    @objc func touchedAction(tap: UITapGestureRecognizer) {
        currentIndex += 1
        if currentIndex < items.count {
            showItem(index: currentIndex)
        }else {
            deleteSelf()
        }
    }
}

// 重写hitTest方法
extension NNGuideView {
    open override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        
        if shouldOnlyWhereTouched {
            return super.hitTest(point, with: event)
        }else {
            if currentIndex < items.count {
                let item = items[currentIndex]
                if item.overlayRect.contains(point) || arrowContainer.frame.contains(point) || introduceLabel.frame.contains(point) {
                    return super.hitTest(point, with: event)
                }else {
                    return nil
                }
            }
            return super.hitTest(point, with: event)
        }
    }
}



class NNArrowLineContainer: UIView {
    
    
    
    override init(frame: CGRect) {
        super.init(frame: CGRect(origin: .zero, size: CGSize(width: 117, height: 117)))
        setupUI()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    fileprivate lazy var imageView: UIImageView = {
        let img = UIImageView(image: UIImage(named: "icon_ea_indicator"))
        img.bounds = CGRect(origin: .zero, size: CGSize(width: 52, height: 117))
        return img
    }()
    
    var direction: NNGuideItem.GuideImageDirection = .top {
        didSet {
            switch direction {
            case .top:
                // 箭头垂直向上
                imageView.transform = CGAffineTransform(rotationAngle: 0)
            case .topRight:
                // 箭头右上
                imageView.transform = CGAffineTransform(rotationAngle: (.pi / 4.0))
            case .topLeft:
                // 箭头左上
                imageView.transform = CGAffineTransform(rotationAngle: -(.pi / 4.0))

            case .bottom:
                // 箭头垂直向下
                imageView.transform = CGAffineTransform(rotationAngle: .pi)

            case .bottomRight:
                // 箭头右下
                imageView.transform = CGAffineTransform(rotationAngle: (.pi * 3.0 / 4.0))
            case .bottomLeft:
                // 箭头左下
                imageView.transform = CGAffineTransform(rotationAngle: -(.pi * 3.0 / 4.0))
            }
        }
    }
    
    
    fileprivate func setupUI() {
        addSubview(imageView)
        imageView.center = center
    }
}
